home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac-Source 1994 July
/
Mac-Source_July_1994.iso
/
C and C++
/
Utilities
/
stevie 3.10
/
mac.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-03
|
14KB
|
727 lines
/*
* Terminal emulator for use with Macintosh and Stevie 3.69.
* Aztec C 3.6c.
* Earle R. Horton 11/23/89.
*/
#include <windows.h>
#include <events.h>
#include <menus.h>
#include <fonts.h>
#include <dialogs.h>
#include <quickdraw.h>
#include <osutils.h>
#include <desk.h>
#include <resources.h>
#include <memory.h>
#include <files.h>
#include <SegLoad.h>
#undef normal
#include "stevie.h"
#define leftoffset 4
#define ORIG_ROWS 24
#define ORIG_COLUMNS 80
short cwd; /* Current working directory. */
char wdname[256]; /* Working directory or volume name. */
static char progname[32]; /* Program name for argv[0]. */
static char pname[32]; /* Program name in Pascal. */
struct Rect dragRect, pRect;
struct WindowRecord wRecord;
struct GrafPort *myWindow, *whichWindow;
struct EventRecord myEvent;
RgnHandle updateRgn;
Boolean dead = false;
short x=0, y=0;
static short escflg = 0, ex, ey, savex, savey;
main()
{
AppFile fParm;
short message, count, index;
Handle apparams;
short refnum;
char **Files;
extern int Rows,Columns;
long stackframeend;
char *lmalloc();
/*
* Here we get the current value of the stack pointer, and set
* the end of the application heap zone to somewhat less than this.
* Then, we remove 128k of memory from the system pool and put it
* in our pool. This helps to prevent frequent calls to malloc()
* from fragmenting the heap. For this to work properly, please
* use an implementation where free() does NOT call DisposPtr().
*
* These numbers, with a 256k MultiFinder partition, give approximately
* the following amounts of storage:
* 25k Stack
* 55k System use (free and relocatable blocks)
* 128k For use by malloc()
* 55k CODE
*/
SetApplLimit( (long)(&stackframeend) - 20000L );
MaxApplZone(); /* We want it. */
free(lmalloc(131072L)); /* Prime the pump. */
/*
* Are there any Files launched from the Finder? If so, build
* a standard C program argument list.
*/
CountAppFiles(&message, &count);
GetAppParms(&pname,&refnum,&apparams);
strcpy(progname,pname);
p2cstr(progname);
Files = (char **)malloc((count+1)*sizeof(char *));
Files[0] = progname;
/*
* Get default volume in case we were invoked with no files.
*/
GetVol(wdname,&cwd);
/* Process the files */
for(index=1;index<=count;index++) {
GetAppFiles(index, &fParm);
ClrAppFiles(index);
Files[index]=(char *)malloc(fParm.fName.length+1);
p2cstr(&fParm.fName);
strcpy(Files[index],&fParm.fName);
/*
* Use as the default directory that directory which holds the last
* file we were invoked with. Problem if we are invoked with files
* in more than one directory and caller does not use pathnames.
*/
wdname[0] = '\0';
cwd = fParm.vRefNum;
}
SetVol(wdname,cwd);
InitGraf(&qd.thePort);
InitWindows();
InitFonts();
setupmenu();
InitDialogs(0L);
InitCursor();
SetRect(&dragRect, 4, 24,
qd.screenBits.bounds.right-4,
qd.screenBits.bounds.bottom-4);
pRect.top = 40;
pRect.left = 5;
pRect.bottom = ORIG_ROWS*12;
pRect.right = (ORIG_COLUMNS+1)*6;
myWindow = NewWindow(
&wRecord,&pRect,pname,true,0,(WindowPtr)-1L,0,0L);
P(P_CO) = Columns = ORIG_COLUMNS;
P(P_LI) = Rows = ORIG_ROWS;
windresize();
SelectWindow(myWindow);
ShowWindow(myWindow);
SetPort(myWindow);
TextFont(4); /* monaco */
TextSize(9);
TextMode(srcCopy);
updateRgn = NewRgn();
xmain(count+1,Files);
}
/*
* This piece of trash serves to allow our window to come up in front
* under MultiFinder. If we have the canBackGround bit set in our
* 'SIZE' resource, then we come up in the background when MultiFinder
* is active. Since we are an interactive application, we want to
* come up in the foreground, with user option to swap us back. Tossing
* a few events (yuch) is the recommended way to get brought forward.
* This code also leaves any startup message on the screen for about
* a half second before we get to work.
*/
void windinit()
{
long time;
time = TickCount() + 30L;
while(time > TickCount()){
(void)GetNextEvent(everyEvent, &myEvent);
}
}
/*
* Resize the window according to the globals Rows and Columns. If window
* contents ever get buffered, this would be the time to reallocate the
* window contents buffer.
*/
windresize()
{
SizeWindow(myWindow,(leftoffset*2)+(Columns*6),Rows*12,false);
}
int inchar()
{
short i = 0,j = 0;
short code;
static long lastblink = 0L;
static Boolean wactive = true;
Boolean on;
long l;
flushbuf();
SetPort(myWindow);
PenMode(patXor);
PenSize(7,11);
MoveTo(leftoffset - 1 + x * 6,y*12);
/*
* Blink the cursor on.
*/
if(wactive){
Line(0,0);
}
on = true;
for(; i == 0 ;){
do{
SystemTask();
/*
* Blink the cursor every GetCaretTime() ticks while waiting for input.
*/
if(wactive){
if(TickCount() > (lastblink + GetCaretTime())){
Line(0,0);
lastblink = TickCount();
on = !on;
}
}
}while (!GetNextEvent(everyEvent, &myEvent));
/*
* Blink the cursor off while servicing events.
*/
if(wactive){
if(on){
Line(0,0);
lastblink = TickCount();
on = false;
}
}
switch(myEvent.what) {
case mouseDown:
code = FindWindow(myEvent.where, &whichWindow);
switch (code) {
case inMenuBar:
docommand(MenuSelect(myEvent.where));
break;
case inSysWindow:
SystemClick(&myEvent, whichWindow);
break;
case inDrag:
DragWindow(whichWindow, myEvent.where, &dragRect);
break;
case inGrow:
case inContent:
if (whichWindow != FrontWindow())
SelectWindow(whichWindow);
else {
}
break;
}
break;
/*
* The next piece of code attempts to get a meaningful ASCII character
* out of the event record. Some translation is done so the program
* doesn't look totally clueless with respect to basic stuff like
* arrow keys and Enter, but very little else is done except to
* map command to control.
*/
case keyDown:
case autoKey:
if (myWindow == FrontWindow()) {
i = myEvent.message & 0xff;
if ((myEvent.modifiers & cmdKey) && (l = MenuKey(i))) {
docommand(l);
i = 0;
}
else if (myEvent.modifiers & cmdKey) {
if ( i == '6'){
i = CTRL('^');
}
else if ( i == '/' ){ /* Actually '?'. */
i = K_HELP;
}else{
i &= 0x1f;
}
}
else if (State == NORMAL){
if ( (i & 0xFF) < 0x20 ){
switch(i){
case CTRL('C'):
i = CTRL('J');
break;
case CTRL('^'):
i = K_UARROW;
break;
case CTRL('_'):
i = K_DARROW;
break;
case CTRL(']'):
i = K_RARROW;
break;
case CTRL('\\'):
i = K_LARROW;
break;
}
}
}
}
break;
case activateEvt:
/*
* If we get an activate event, then blink the cursor on.
*/
if(myEvent.message == (long)myWindow){
if (myEvent.modifiers & activeFlag) {
wactive = true;
}else{
wactive = false;
if(on){
Line(0,0);
lastblink = TickCount();
on = false;
}
}
}
break;
case updateEvt:
if(myEvent.message == (long)myWindow){
SetPort(myWindow);
BeginUpdate(myWindow);
redrawit();
EndUpdate(myWindow);
}
break;
}
}
return i;
}
/*
* Redraw the window contents. Currently has the host program do this.
* A better alternative would be to maintain a character buffer to store
* the window contents and take care of this here.
*/
redrawit()
{
int savex,savey;
if(!dead){
savex = x;
savey = y;
screenclear();
updatescreen();
flushbuf();
x = savex;
y = savey;
MoveTo(leftoffset - 1 + x * 6,y*12);
}
}
#undef exit
void windexit(status)
int status;
{
if(status){
ParamText(pname,pname,pname,pname);
Alert(128,nil);
}
exit(status);
}
/*
* Substitute for [f]printf in the Mac environment.
* A more sophisticated approach might be to intercept write calls,
* but each compiler probably implements these differently.
*/
#undef fprintf
#undef printf
myfprintf(a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac)
FILE *a1;
char *a2;
long a3,a4,a5,a6,a7,a8,a9,aa,ab,ac;
{
char sbuf[2048];
char *s,c;
if( a1 == stderr || a1 == stdout || a1 == stdin ){
sprintf(sbuf,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac);
s = &sbuf[0];
for(;(c = *s++);){
switch (c){
case NL:
case CR:
outchar(0x0a);
outchar(0x0d);
break;
default:
outchar(c);
break;
}
}
flushbuf();
}else{
fprintf(a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac);
}
}
/*
* Characters are generally buffered, which means we can use StdText()
* to draw a bunch of them. This is faster than repeated calls to
* DrawChar().
*/
#define BSIZE 128
static char outbuf[BSIZE];
static int bpos = 0;
void
flushbuf()
{
if (bpos != 0){
MoveTo((x*6)+leftoffset, (y*12)+9);
StdText((short)bpos,outbuf,0x00010001,0x00010001);
x += bpos;
bpos = 0;
}
}
/*
* Entry point to draw characters on the screen. Buffer them up until
* a control character appears or the buffer becomes full.
*/
void outchar(c)
register unsigned char c;
{
if(c < 0x20 || escflg != 0) {
flushbuf();
scrput(c);
}
else{
outbuf[bpos++] = c;
if (bpos >= BSIZE)
flushbuf();
}
}
void outstr(s)
register char *s;
{
while(*s){
outchar(*s++);
}
}
void beep()
{
scrput('\007');
}
void remove(file)
char *file;
{
char fsfile[256];
strcpy(fsfile,file);
c2pstr(fsfile);
FSDelete(fsfile,cwd);
}
void rename(of,nf)
char *of,*nf;
{
char fsof[256],fsnf[256];
strcpy(fsof,of);
strcpy(fsnf,nf);
c2pstr(fsof);
c2pstr(fsnf);
SetVol(wdname,cwd);
Rename(fsof,cwd,fsnf);
}
csave()
{
savex = x;
savey = y;
}
crestore()
{
x = savex;
y = savey;
}
static
del_lin(lin)
{
struct Rect rect;
rect.left = 0;
rect.right = ((GrafPtr)myWindow)->portRect.right;
rect.top = lin * 12;
rect.bottom = ((GrafPtr)myWindow)->portRect.bottom;
ScrollRect(&rect, 0, -12, updateRgn);
}
static
ins_lin(lin)
{
struct Rect rect;
rect.left = 0;
rect.right = ((GrafPtr)myWindow)->portRect.right;
rect.top = lin * 12;
rect.bottom = ((GrafPtr)myWindow)->portRect.bottom;
ScrollRect(&rect, 0, 12, updateRgn);
}
static
clr_eol()
{
struct Rect rect;
rect.left = leftoffset + x * 6;
rect.top = y * 12;
rect.right = ((GrafPtr)myWindow)->portRect.right;
rect.bottom = rect.top + 13;
EraseRect(&rect);
}
scrput(c)
register unsigned char c;
{
register short i;
struct Rect r;
GrafPtr tmpport;
GetPort(&tmpport);
SetPort(myWindow);
switch(escflg) {
case 0:
switch(c) {
case 0x1b:
escflg = 1;
return;
case 0x07:
SysBeep(1);
break;
case 0x08:
if (x)
x--;
break;
case 0x09:
c = ((x + 4) & ~3) - x;
while(c--)
scrput(' ');
return;
case 0x0a:
if( y < (myWindow->portRect.bottom/12) - 1 )
y++;
else del_lin(0);
break;
case 0x0d:
x = 0;
break;
default:
if (c >= 0x20){
outbuf[bpos++] = c;
if (bpos >= BSIZE)
flushbuf();
}
break;
}
break;
case 1:
switch(c) {
case 'R':
del_lin(y);
x = 0;
break;
case 'E':
ins_lin(y);
x = 0;
break;
case 'T':
clr_eol();
break;
case '=':
escflg = 2;
return;
case ';':
EraseRect(&qd.thePort->portRect);
x = y = 0;
break;
case '7':
csave();
break;
case '8':
crestore();
break;
default:
break;
}
escflg = 0;
break;
case 2:
ey = c - ' ';
escflg++;
break;
case 3:
ex = c - ' ';
escflg = 0;
if (ey >= 0 && ex >= 0) {
y = ey;
x = ex;
}
break;
}
SetPort(tmpport);
}
void windgoto(r,c)
register int r,c;
{
char cbuf[20];
sprintf(cbuf,"\033=%c%c",r + ' ',c + ' ');
outstr(cbuf);
}
#define appleMenu 255
#define fileMenu 256
#define editMenu 257
#define NMENUS 3
MenuHandle myMenus[NMENUS];
setupmenu()
{
short i;
char about[256];
InitMenus();
myMenus[0] = GetMenu(appleMenu);
GetItem(myMenus[0],1,about);
p2cstr(about);
strcat(about,progname);
strcat(about,"…");
c2pstr(about);
SetItem(myMenus[0],1,about);
AddResMenu(myMenus[0], 'DRVR');
myMenus[1] = GetMenu(fileMenu);
myMenus[2] = GetMenu(editMenu);
for (i=0;i<NMENUS;i++)
InsertMenu(myMenus[i], 0);
DrawMenuBar();
}
docommand(mResult)
long mResult;
{
register short i;
short theItem, theMenu;
char name[40];
int savex,savey;
theMenu = mResult >> 16;
theItem = mResult;
switch(theMenu) {
case appleMenu:
if (theItem == 1) {
savex = x;savey = y;
help();
redrawit();
x = savex;y = savey;
MoveTo(leftoffset - 1 + x * 6,y*12);
}
else{
GetItem(myMenus[0], theItem, name);
OpenDeskAcc(name);
}
break;
case fileMenu:
windexit();
break;
case editMenu:
(void)SystemEdit(theItem - 1);
break;
}
HiliteMenu(0);
}
#undef fopen
FILE *
fopenb(fname, mode)
char *fname;
char *mode;
{
char pname[256];
FInfo info;
if ( mode[0] == 'w' ) {
strcpy(pname,fname);
c2pstr(pname);
if(GetFInfo(pname,cwd,&info) != noErr){
Create(pname,cwd,'STvi','TEXT');
}
}
SetVol(wdname,cwd);
return fopen(fname, mode);
}
void
doshell()
{
}
system()
{
}
/*
* delay() is called to flash to matching braces when showmatch is on
* in Stevie. This version turns on the cursor, pauses for a bit, then
* turns off the cursor.
*/
void
delay()
{
long dtime = 6L;
SetPort(myWindow);
PenMode(patXor);
PenSize(7,11);
MoveTo(leftoffset - 1 + x * 6,y*12);
Line(0,0);
Delay(dtime,&dtime);
Line(0,0);
}
sleep()
{
}
/*
* "Environment variables" are stored as named resources of type 'STR '.
*/
char *getenv(str)
char str[];
{
char pname[256];
static char result[256];
char **envstr;
strcpy(pname,str);
c2pstr(pname);
if((envstr = (char **)GetNamedResource('STR ',pname)) != nil){
HLock(envstr);
p2cstr(*envstr);
strcpy(result,*envstr);
ReleaseResource(envstr);
return result;
}
else return (char *)0L;
}